home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 2000 November: Tool Chest / Dev.CD Nov 00 TC Disk 1.toast / Sample Code / Archive / Graphics / QuickDraw GX / GX->PostScript Sample / GXToPostScript / Imaging Engine / MiscServices.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-09-28  |  32.2 KB  |  1,471 lines  |  [TEXT/MPS ]

  1. /*
  2.      File:        MiscServices.c
  3.  
  4.      Contains:    QuickDraw GX to PostScript conversion code.
  5.                          Miscellanious test routines
  6.                         PSPrimitiveShape
  7.                         PSGetColorSpaceBasis
  8.                         Miscellanious shape service routines
  9.  
  10.      Version:    Technology:    Quickdraw GX 1.1.x
  11.       
  12.      Copyright:    © 1990-1997 by Apple Computer, Inc., all rights reserved.
  13. */
  14.  
  15. #include "GXToPSBuildConfig.h"
  16. #include <GXGraphics.h>
  17. #include "GXGraphicsPriv.h"
  18. #include "GXToPostScript.h"
  19. #include "IOUtilities.h"
  20. #include "RDUtil.h"
  21. #include "FontHandler.h"
  22. #include "PublicPostScriptIE.h"
  23. #include "private.h"
  24. #include "PSIEResources.h"
  25. #include "GXErrors.h"
  26. #include "ShapeUtilities.h"
  27.  
  28. #ifdef resumeLabel
  29.     #undef resumeLabel
  30. #endif
  31. #define resumeLabel(exception)
  32.  
  33.  
  34.  
  35.  
  36.  
  37.  
  38.  
  39. //<FF>
  40. /******************************************
  41.     The following routines are for the disposing
  42.     and comparison of graphics objects, allowing for
  43.     the nil case
  44. *******************************************/
  45. Boolean    PSEqualColorSet(gxColorSet set1, gxColorSet set2)
  46.     {
  47.         if ( (set1 == nil) && (set2 == nil))
  48.             return(true);
  49.         else if (set1 == nil)
  50.             return(false);
  51.         else if (set2 == nil)
  52.             return(false);
  53.         else
  54.             return(GXEqualColorSet(set1, set2));
  55.             
  56.     }//PSEqualColorSet
  57.  
  58.  
  59. void PSDisposeColorSet(gxColorSet theSet)
  60.     {
  61.         if (theSet != nil)
  62.             GXDisposeColorSet(theSet);
  63.             
  64.     }//PSDisposeColorSet
  65.  
  66.  
  67. //<FF>
  68. /********************************************
  69.     The following routines are for the checking
  70.     of equality between objects (styles, inks, and transforms)
  71.     They also check for the equality of any PostScript tags
  72.     which the gx graphics routines wouldn't do
  73.     
  74. **********************************************/
  75. Boolean    PSEqualInk(gxInk ink1, gxInk ink2)
  76.     {
  77.         long        nTags1, nTags2, i;
  78.         gxTag        tag1, tag2;
  79.         Boolean result;
  80.         
  81.         result = GXEqualInk(ink1, ink2);
  82.         
  83.         if (result) {                    // Equal returned true, check tags.
  84.  
  85.             nTags1 = GXGetInkTags(ink1, gxPostScriptTag, 1, gxSelectToEnd, nil);
  86.             nTags2 = GXGetInkTags(ink2, gxPostScriptTag, 1, gxSelectToEnd, nil);
  87.             
  88.             if (nTags1 != nTags2) {
  89.             
  90.                 result = false;
  91.                 
  92.             } else if (nTags1 != 0) {            // If they have the same number of tags (non-zero) compare them
  93.             
  94.                 for (i = 1; i <= nTags1; ++i) {
  95.                 
  96.                     GXGetInkTags(ink1, gxPostScriptTag, i, 1, &tag1);
  97.                     GXGetInkTags(ink2, gxPostScriptTag, i, 1, &tag2);
  98.                     
  99.                     result = GXEqualTag(tag1, tag2);
  100.                     if (!result) 
  101.                         break;
  102.             
  103.                 }//end for
  104.             
  105.             }//end if
  106.         
  107.         
  108.         }//end if
  109.     
  110.         return(result);
  111.         
  112.     }//PSEqualInk
  113.  
  114.  
  115.  
  116. Boolean    PSEqualStyle(gxStyle style1, gxStyle style2)
  117.     {
  118.         long        nTags1, nTags2, i;
  119.         gxTag        tag1, tag2;
  120.         Boolean result;
  121.         
  122.         result = GXEqualStyle(style1, style2);
  123.         
  124.         if (result) {                    // Equal returned true, check tags.
  125.  
  126.             nTags1 = GXGetStyleTags(style1, gxPostScriptTag, 1, gxSelectToEnd, nil);
  127.             nTags2 = GXGetStyleTags(style2, gxPostScriptTag, 1, gxSelectToEnd, nil);
  128.             
  129.             if (nTags1 != nTags2) {
  130.             
  131.                 result = false;
  132.                 
  133.             } else if (nTags1 != 0) {            // If they have the same number of tags (non-zero) compare them
  134.             
  135.                 for (i = 1; i <= nTags1; ++i) {
  136.                 
  137.                     GXGetStyleTags(style1, gxPostScriptTag, i, 1, &tag1);
  138.                     GXGetStyleTags(style2, gxPostScriptTag, i, 1, &tag2);
  139.                     
  140.                     result = GXEqualTag(tag1, tag2);
  141.                     if (!result) 
  142.                         break;
  143.             
  144.                 }//end for
  145.             
  146.             }//end if
  147.         
  148.         
  149.         }//end if
  150.     
  151.         return(result);
  152.         
  153.     }//PSEqualStyle
  154.  
  155.  
  156.  
  157. Boolean    PSEqualTransform(gxTransform transform1, gxTransform transform2)
  158.     {
  159.         long        nTags1, nTags2, i;
  160.         gxTag        tag1, tag2;
  161.         Boolean result;
  162.         
  163.         //dprintf(trace, "%X vs. %X", transform1, transform2);
  164.         
  165.         result = GXEqualTransform(transform1, transform2);
  166.         
  167.         if (result) {                    // Equal returned true, check tags.
  168.  
  169.             nTags1 = GXGetTransformTags(transform1, gxPostScriptTag, 1, gxSelectToEnd, nil);
  170.             nTags2 = GXGetTransformTags(transform2, gxPostScriptTag, 1, gxSelectToEnd, nil);
  171.             
  172.             if (nTags1 != nTags2) {
  173.             
  174.                 result = false;
  175.                 
  176.             } else if (nTags1 != 0) {            // If they have the same number of tags (non-zero) compare them
  177.             
  178.                 for (i = 1; i <= nTags1; ++i) {
  179.                 
  180.                     GXGetTransformTags(transform1, gxPostScriptTag, i, 1, &tag1);
  181.                     GXGetTransformTags(transform2, gxPostScriptTag, i, 1, &tag2);
  182.                     
  183.                     result = GXEqualTag(tag1, tag2);
  184.                     if (!result) 
  185.                         break;
  186.             
  187.                 }//end for
  188.             
  189.             }//end if
  190.         
  191.         
  192.         }//end if
  193.     
  194.         return(result);
  195.         
  196.     }//PSEqualTransform
  197.  
  198.  
  199.  
  200.  
  201.  
  202. //<FF>
  203. /******************
  204.  
  205.         misc test routines
  206.         
  207.                 TestInkModeCopy
  208.                 TestInkModeOr
  209.                 TestMappingPerspective
  210.                 TestMappingIdentity
  211.                 TestMappingEqual
  212.                 TestShapeSquare
  213.                 TestShapeOval
  214.                 TestStyleDash
  215.                                 
  216. ******************/
  217.  
  218. #ifdef needTestShapeSquare
  219. /***********************************
  220.     TestShapeSquare:
  221.     
  222.     Is the shape a Square.
  223.     
  224.     If it is, return the width and center.
  225.     If it is not, the width and center are left untouched.
  226.     
  227. ************************************/
  228. Boolean TestShapeSquare(gxShape theShape, fixed *width, point *center)
  229.     {
  230.         Boolean                        isSquare = false;
  231.         rectangle                    aRect;
  232.         register fixed        theWidth, theHeight;
  233.         
  234.         if ( GetShapeType(theShape) == rectangleType ) {
  235.         
  236.             GetRectangle(theShape, &aRect);        
  237.             theHeight = aRect.bottom - aRect.top;
  238.             theWidth = aRect.right - aRect.left;
  239.             
  240.             if (theWidth == theHeight) {
  241.             
  242.                 isSquare = true;
  243.                 *width = theWidth;
  244.                 center->x = aRect.left + (theWidth >> 1);
  245.                 center->y = aRect.top + (theHeight >> 1);
  246.         
  247.             }//end if
  248.             
  249.         }//end if
  250.     
  251.         return(isSquare);
  252.         
  253.     }//TestShapeSquare;
  254.  
  255. #endif
  256.  
  257.  
  258.  
  259. //<FF>
  260. /******************************
  261.     TestStyleDash:
  262.     
  263.     Returns true if the style contains a dash shape
  264.     or a dash synonym.
  265.     
  266. *******************************/
  267. Boolean TestStyleDash(gxStyle theStyle)
  268.     {
  269.         if (GXGetStyleTags(theStyle, gxDashSynonymTag, 1, 1, nil))
  270.             return(true);
  271.         else
  272.             return ( DoesStyleHaveDash(theStyle) );
  273.         
  274.     }//TestStyleDash
  275.  
  276. //<FF>
  277. /******************************
  278.     TestStylePattern:
  279.     
  280.     Returns true if the style contains a pattern shape
  281.     
  282. *******************************/
  283. Boolean TestStylePattern(gxStyle theStyle)
  284.     {
  285.         return ( DoesStyleHavePattern(theStyle) );
  286.                 
  287.     }//TestStylePattern
  288.  
  289.  
  290.  
  291. /**************
  292.     Routine checks for or-mode
  293.     based on tag.  The transfer mode
  294.     resolver is supposed to tag or-mode
  295.     inks so we don't have to do the
  296.     work over again
  297. ***************/
  298. short    TestInkModeOr( gxInk shInk )
  299.     {
  300.         short        mode = 0;            // copy mode.
  301.         gxTag        orTag;
  302.         long        size;
  303.         
  304.         if (GXGetInkTags(shInk, ormd, 1, gxSelectToEnd, nil)) {
  305.     
  306.             GXGetInkTags(shInk, ormd, 1, 1, &orTag);
  307.             GXLockTag(orTag);
  308.             mode = *(short*)GXGetTagStructure(orTag, &size);            // Get the transfer mode value.
  309.             GXUnlockTag(orTag);
  310.             
  311.             if ((size == 0) || (mode > 7))            // Avoid PostScript error.
  312.                 mode = 0;
  313.                         
  314.             /*****
  315.                 Tag is 1: SrcOr, 3: SrcBic, 5: NotSrcOr, 7: NotSrcBic
  316.                 Convert to:
  317.                              1: SrcOr, 2: SrcBic, 3: NotSrcOr, 4: NotSrcBic
  318.             *****/
  319.             
  320.             mode = (mode >> 1) + 1;            
  321.     
  322.         }//end if
  323.         
  324.         return(mode);
  325.     
  326.     }//TestInkModeOr
  327.  
  328.  
  329.  
  330.  
  331.  
  332.  
  333. Boolean TestMappingEqual( gxMapping *oneMapping, gxMapping *twoMapping )
  334.     {
  335.         long    indx = ( sizeof( gxMapping ) >> 2 );
  336.         
  337.         register short i;
  338.         
  339.         
  340.         register Fixed    *onePtr = &(oneMapping->map[0][0]);
  341.         register Fixed    *twoPtr = &(twoMapping->map[0][0]);
  342.         
  343.         for (i = 8; i >= 0; --i)
  344.             if (*onePtr++ != *twoPtr++)
  345.                 break;
  346.             
  347.         return( i < 0 );
  348.     }
  349.  
  350.  
  351. Boolean TestMappingPerspective( gxMapping *theMapping)
  352.     {
  353.         /* If the mapping has anything other than 0 0 X in the last column, it is a perspective */
  354.         
  355.         return (
  356.                             (theMapping->map[0][2] != 0 ) ||
  357.                             (theMapping->map[1][2] != 0 )
  358.                      );
  359.         
  360.     }//TestMappingForPerspective
  361.  
  362.  
  363. Boolean TestMappingIdentity( gxMapping *theMapping)
  364.     {
  365.         register Fixed        *mapElement;
  366.  
  367.         mapElement = &(theMapping->map[0][0]);
  368.                     
  369.         /** Note, this expression depends on evaluation in left-right order **/
  370.         
  371.         return( (*mapElement++ == ff(1)) &&
  372.                         (*mapElement++ == ff(0)) &&
  373.                         (*mapElement++ == ff(0)) &&
  374.                         
  375.                         (*mapElement++ == ff(0)) &&
  376.                         (*mapElement++ == ff(1)) &&
  377.                         (*mapElement++ == ff(0)) &&
  378.                         
  379.                         (*mapElement++ == ff(0)) &&
  380.                         (*mapElement++ == ff(0)) &&
  381.                         (*mapElement   == fract1)
  382.                     );    
  383.     }
  384.  
  385.  
  386.  
  387. void DoNothingNoticeFunction( gxGraphicsNotice theNotice )
  388. {
  389.     #pragma unused( theNotice )
  390. }
  391.  
  392.  
  393.  
  394. //<FF>
  395. /**********************************
  396.     Routine:        ResetShapeStyle:
  397.     
  398.     sets a shape's style to be the default style.
  399.     
  400. ***********************************/
  401. void ResetShapeStyle(gxShape theShape)
  402.     {
  403.         gxStyle            theStyle, aStyle;
  404.         
  405.         theStyle = GXGetShapeStyle(theShape);
  406.         if (GXGetStyleOwners(theStyle) == 1) {
  407.         
  408.             GXResetStyle(theStyle);
  409.         
  410.         } else {
  411.         
  412.             aStyle = GXNewStyle();
  413.             GXResetStyle(aStyle);
  414.             GXSetShapeStyle(theShape, aStyle);
  415.             GXDisposeStyle(aStyle);
  416.         
  417.         }//end if
  418.     
  419.     }//ResetShapeStyle
  420.  
  421.  
  422. //<FF>
  423. /**********************************
  424.     Routine:        ResetShapeTransform:
  425.     
  426.     sets a shape's style to be the default style.
  427.     
  428. ***********************************/
  429. void ResetShapeTransform(gxShape theShape)
  430.     {
  431.         gxTransform            theTransform, aTransform;
  432.         
  433.         theTransform = GXGetShapeTransform(theShape);
  434.         if (GXGetTransformOwners(theTransform) == 1) {
  435.         
  436.             GXResetTransform(theTransform);
  437.         
  438.         } else {
  439.         
  440.             aTransform = GXNewTransform();
  441.             GXResetTransform(aTransform);
  442.             GXSetShapeTransform(theShape, aTransform);
  443.             GXDisposeTransform(aTransform);
  444.         
  445.         }//end if
  446.     
  447.     }//ResetShapeTransform
  448.  
  449.  
  450.  
  451. //<FF>
  452. /**************************
  453.     PSPrimitiveShape:
  454.     
  455.     Calls PrimitiveShape but selectively applies
  456.     style attributes instead of all style attributes.
  457.     
  458. ***************************/
  459. OSErr PSPrimitiveShape(gxShape theShape, TIEPrimitiveFlags flags)
  460.     {
  461.         gxPatternRecord        thePattern;
  462.         gxDashRecord            theDash;
  463.         gxJoinRecord            theJoin;
  464.         gxCapRecord                theCaps;
  465.         Fixed                            penSize;
  466.                 
  467.         /** Remove style attributes we don't want PrimitiveShape to apply **/
  468.         
  469.         if (!(flags & eApplyDash)) {
  470.         
  471.             GXGetShapeDash(theShape, &theDash);
  472.             GXSetShapeDash(theShape, nil);
  473.             
  474.         }//end if
  475.         
  476.         if (!(flags & eApplyPattern)) {
  477.         
  478.             GXGetShapePattern(theShape, &thePattern);
  479.             GXSetShapePattern(theShape, nil);
  480.             
  481.         }//end if
  482.     
  483.         if (!(flags & eApplyJoin)) {
  484.         
  485.             GXGetShapeJoin(theShape, &theJoin);
  486.             GXSetShapeJoin(theShape, nil);
  487.             
  488.         }//end if
  489.     
  490.         if (!(flags & eApplyCaps)) {
  491.  
  492.             GXGetShapeCap(theShape, &theCaps);
  493.             GXSetShapeCap(theShape, nil);
  494.             
  495.         }//end if
  496.         
  497.         
  498.         if (!(flags & eApplyPen)) {
  499.         
  500.             penSize = GXGetShapePen(theShape);
  501.             GXSetShapePen(theShape, 0);
  502.             
  503.         }//end if
  504.         
  505.         
  506.         
  507.         
  508.         /** Do it! **/
  509.         GXPrimitiveShape(theShape);
  510.  
  511.         /** Now put back any style attributes we didn't apply **/
  512.     
  513.         if (!(flags & eApplyDash)) {
  514.             
  515.             if (theDash.dash != nil) {
  516.                 GXSetShapeDash(theShape, &theDash);
  517.                 GXDisposeShape(theDash.dash);
  518.             }//end if
  519.             
  520.         } else {
  521.         
  522.             GXSetShapeDash(theShape, nil);
  523.         
  524.         }//end if
  525.         
  526.  
  527.         if (!(flags & eApplyPattern)) {
  528.         
  529.             if (thePattern.pattern != nil) {
  530.                 GXSetShapePattern(theShape, &thePattern);
  531.                 GXDisposeShape(thePattern.pattern);
  532.             }//end if
  533.             
  534.         } else {
  535.         
  536.             GXSetShapePattern(theShape, nil);
  537.         
  538.         }//end if
  539.     
  540.  
  541.         if (!(flags & eApplyJoin)) {
  542.         
  543.             GXSetShapeJoin(theShape, &theJoin);
  544.             if (theJoin.join != nil)
  545.                 GXDisposeShape(theJoin.join);
  546.                 
  547.         } else {
  548.         
  549.             GXSetShapeJoin(theShape, nil);
  550.             
  551.         }//end if
  552.     
  553.  
  554.         if (!(flags & eApplyCaps)) {
  555.                                 
  556.             GXSetShapeCap(theShape, &theCaps);
  557.             
  558.             if (theCaps.startCap != nil)
  559.                 GXDisposeShape(theCaps.startCap);
  560.                 
  561.             if (theCaps.endCap != nil)
  562.                 GXDisposeShape(theCaps.endCap);
  563.             
  564.         }//end if
  565.  
  566.  
  567.         if (!(flags & eApplyPen)) {
  568.         
  569.             GXSetShapePen(theShape, penSize);
  570.             
  571.         } else {
  572.         
  573.             /*************************************
  574.                     Make the shape hairline becuase if
  575.                     we primitivized a frame shape that
  576.                     was capped or dashed or joined with 
  577.                     a framed shape, then the PrimitiveShape
  578.                     would add the hairline contours of the
  579.                     dash, cap, or join.  When drawn they 
  580.                     must stay hairlines so the parent shape
  581.                     must be hairline
  582.             **************************************/
  583.             GXSetShapePen(theShape, 0);
  584.         
  585.         }//end if
  586.  
  587.  
  588.         return(GXGetGraphicsError(nil));
  589.         
  590.     }//PSPrimitiveShape
  591.  
  592.  
  593. //<FF>
  594. /******************************************
  595.  
  596.     Routine:    ConcatTransform
  597.     
  598.     Routine concatenates two transforms.
  599.     
  600.         Combines the source's mapping and clip with the operand.
  601.         
  602.             Make a transfrom such that a shape drawn through it
  603.              produces the same result as drawing a picture with sourc transform
  604.              containing shape with operand trasnsform.
  605.     
  606. *******************************************/
  607. void ConcatTransform(gxTransform source, gxTransform operand)
  608.     {
  609.         gxMapping            sourceMapping, operandMapping, combinedMapping, invertedeMapping;
  610.         gxShape                sourceClip,    operandClip;
  611.         
  612.         /* Get transform data */
  613.         
  614.         GXGetTransformMapping(source, &sourceMapping);
  615.         sourceClip = GXGetTransformClip(source);
  616.         
  617.         GXGetTransformMapping(operand, &operandMapping);
  618.         operandClip = GXGetTransformClip(operand);
  619.                 
  620.         /* Concatenate the two mappings */
  621.         
  622.         CopyToMapping(&combinedMapping, &operandMapping);
  623.         MapMapping( &combinedMapping, &sourceMapping);
  624.         
  625.         /* Map the operand clip through the operand mapping, puts clip in source mapping space */
  626.  
  627.         GXSetShapeAttributes(operandClip, GXGetShapeAttributes(operandClip) & ~gxMapTransformShape);
  628.         GXMapShape(operandClip, &operandMapping);
  629.         
  630.         /* Combine the oprand mapped oprand clip with the source clip */
  631.         
  632.         IntersectShapeAndBitmap(sourceClip, operandClip);
  633.         
  634.         /* Combined clip is in sourceMapping space, Put it into space of combined mapping */
  635.         
  636.         InvertMapping(&invertedeMapping, &operandMapping);
  637.         GXMapShape(sourceClip, &invertedeMapping);
  638.         
  639.         /* Make the source transform */
  640.         
  641.         GXSetTransformMapping(source, &combinedMapping);
  642.         GXSetTransformClip(source, sourceClip);
  643.  
  644.         /* clean up */
  645.         
  646.         GXDisposeShape(sourceClip);
  647.         GXDisposeShape(operandClip);
  648.         
  649.     
  650.     }//ConcatTransforms
  651.  
  652. //<FF>
  653. /******************************************
  654.     Routine MapWholeShape:
  655.     
  656.     Routine does what MapShape does, except that
  657.     it forces mapping of geometries, handles extra
  658.     clip generated by mapping bitmaps, and also maps
  659.     the shape's clip and style through the mapping
  660.     
  661.     The shape that results from this will have an identity
  662.     mapping and drawing it should produce the same result
  663.     as having drawn the shape with the provided mapping.
  664.     
  665.     Since this routine affects the geometry of a shape,
  666.     any PostScript synonyms will be tossed.
  667.     
  668.     pass nil for mappingToUse to use shape's own mapping.
  669.     
  670. *******************************************/
  671. OSErr MapWholeShape(gxShape theShape, gxMapping *mappingToUse)
  672.     {
  673.         gxShape            clipShape;
  674.         gxMapping        shapesMapping;
  675.         gxMapping        *theMapping;
  676.         
  677.         if (mappingToUse == nil) {
  678.  
  679.             GXGetShapeMapping(theShape, &shapesMapping);
  680.             theMapping = &shapesMapping;
  681.         
  682.         } else {
  683.         
  684.             theMapping = mappingToUse;
  685.         
  686.         }//end if
  687.                 
  688.         /* Map the clip through the mapping */
  689.         
  690.         clipShape = GXGetShapeClip(theShape);
  691.         GXSetShapeAttributes(clipShape, GXGetShapeAttributes(clipShape) & ~gxMapTransformShape);
  692.         GXMapShape(clipShape, theMapping);
  693.         
  694.         /** Now call make the shape primitive so that all style geometries are also mapped **/
  695.         
  696.         GXPrimitiveShape(theShape);
  697.         ResetShapeStyle(theShape);
  698.  
  699.         /* Let MapShape think there is no clip, I don't know what it might do with it for bitmaps */
  700.         
  701.         GXSetShapeClip(theShape, nil);
  702.         
  703.         GXSetShapeAttributes(theShape, GXGetShapeAttributes(theShape) & ~gxMapTransformShape);
  704.         
  705.         #ifdef printBounds
  706.         if ( GXGetShapeType(theShape) == gxBitmapType ) {
  707.         
  708.             gxPoint                    points[2];
  709.             gxBitmap                theBits;
  710.             
  711.             dprintf(trace, "About to map bitmap shape through:\n%M", theMapping);
  712.             GXGetBitmap(theShape, &theBits, &points[0]);
  713.             points[1].x = points[0].x + ff(theBits.width - 1);
  714.             points[1].y = points[0].y + ff(theBits.height - 1);
  715.             
  716.             dprintf(trace, "Old bounds: %F %F %F %F", points[0].x, points[0].y, points[1].x, points[1].y);
  717.             MapPoints(theMapping, 2, points);
  718.             dprintf(trace, "New bounds: %F %F %F %F", points[0].x, points[0].y, points[1].x, points[1].y);
  719.  
  720.         }//end if
  721.         #endif
  722.         
  723.         GXMapShape(theShape, theMapping);
  724.         
  725.         /* If the shape was a bitmap, MapShape may have added a clip, get it. */
  726.         
  727.         if (GXGetShapeType(theShape) == gxBitmapType) {
  728.         
  729.             gxShape newClip = GXGetShapeClip(theShape);        // Get clip generated by MapShape
  730.  
  731.             GXIntersectShape(clipShape, newClip);                    // and intersect it with old clip.
  732.             GXDisposeShape(newClip);
  733.             
  734.         }//end if
  735.         
  736.         ResetShapeTransform(theShape);                        // Give the shape the identity transform
  737.         GXSetShapeClip(theShape, clipShape);            // Give the shape the mapped clip.
  738.                 
  739.         GXDisposeShape(clipShape);
  740.         
  741.         
  742.         /** Now dispose of any PostScript synonyms **/
  743.         
  744.         GXSetShapeTags(theShape, gxPostScriptTag, 1, gxSelectToEnd, 0, nil);
  745.         GXSetShapeTags(theShape, gxPostControlTag, 1, gxSelectToEnd, 0, nil);
  746.  
  747.         return( GXGetGraphicsError(nil) );
  748.     
  749.     }//MapWholeShape
  750.  
  751.     
  752.  
  753.  
  754.  
  755.  
  756. //<FF>
  757. /***********************************
  758.     DoFillKey:
  759.     
  760.     Routine outputs the correct PostScript
  761.     Fill key for the gx graphic fill type
  762.     
  763. *************************************/
  764. OSErr DoFillKey(TRDParams* pRDParams, gxShapeFill theFill)
  765.     {
  766.         OSErr            status;
  767.         
  768.         pRDParams->resIndex = kFillKey;
  769.         
  770.         switch (theFill) {
  771.  
  772.             case gxEvenOddFill:
  773.                 status = RDResPrintf(pRDParams, kEvenOddFillKey);
  774.                 break;
  775.                 
  776.             case gxFrameFill:
  777.             case gxClosedFrameFill:
  778.                 status = RDResPrintf(pRDParams, kFrameFillKey);
  779.                 break;
  780.             
  781.             case gxWindingFill:
  782.                 status = RDResPrintf(pRDParams, kWindingFillKey);
  783.                 break;
  784.                 
  785.             case gxInverseFill:
  786.                 status = RDResPrintf(pRDParams, kInverseFillKey);
  787.                 break;
  788.  
  789.             case gxNoFill:
  790.                 status = RDResPrintf(pRDParams, kNoFillKey);
  791.                 break;
  792.                 
  793.             default:
  794.                 status = noErr;
  795.                 break;
  796.         
  797.         }//end switch(theFill)
  798.         
  799.         ncheck(status);
  800.     
  801.         return(status);    
  802.     
  803.     }//DoFillKey
  804.  
  805. //<FF>
  806. /*********************************
  807.     DoBeginProcedure:
  808.     
  809.     Routine outputs the Proper PostScript
  810.     for beginning a procedure definition
  811.     
  812. **********************************/
  813. OSErr DoBeginProcedure(TIEGlobalsHdl hGlobals)
  814.     {
  815.         OSErr                                status;
  816.         unsigned char                OpenCurlyBrace = '{';
  817.     
  818.         status = PSIEBufferData(hGlobals, &OpenCurlyBrace, 1, gxNoBufferOptions);
  819.         ncheck(status);
  820.         
  821.         return(status);
  822.         
  823.     }//DoBeginProcedure
  824.  
  825.  
  826. //<FF>
  827. /*********************************
  828.     DoEndProcedure:
  829.     
  830.     Routine outputs the Proper PostScript
  831.     for ending a procedure definition
  832.     
  833. **********************************/
  834. OSErr DoEndProcedure(TIEGlobalsHdl hGlobals)
  835.     {
  836.         OSErr                                        status;
  837.         unsigned        char                CloseCurlyBrace = '}';
  838.     
  839.         status = PSIEBufferData(hGlobals, &CloseCurlyBrace, 1, gxNoBufferOptions);
  840.         ncheck(status);
  841.         
  842.         return(status);
  843.         
  844.     }//DoEndProcedure
  845.  
  846.  
  847. //<FF>
  848. /*********************************
  849.     DoBeginArray:
  850.     
  851.     Routine outputs the Proper PostScript
  852.     for beginning an array definition
  853.     
  854. **********************************/
  855. OSErr DoBeginArray(TIEGlobalsHdl hGlobals)
  856.     {
  857.         OSErr                            status;
  858.         unsigned char            beginArray[] = "[\n";
  859.     
  860.         status = PSIEBufferData(hGlobals, beginArray, 2, gxNoBufferOptions);
  861.         ncheck(status);
  862.         
  863.         return(status);
  864.         
  865.     }//DoBeginArray
  866.  
  867.  
  868. //<FF>
  869. /*********************************
  870.     DoEndArray:
  871.     
  872.     Routine outputs the Proper PostScript
  873.     for ending an array definition
  874.     
  875. **********************************/
  876. OSErr DoEndArray(TIEGlobalsHdl hGlobals)
  877.     {
  878.         OSErr                        status;
  879.         unsigned char        endArray[] = "]\n";
  880.     
  881.         status = PSIEBufferData(hGlobals, endArray, 2, gxNoBufferOptions);
  882.         ncheck(status);
  883.         
  884.         return(status);
  885.         
  886.     }//DoEndArray
  887.  
  888.  
  889.  
  890.  
  891.  
  892. //<FF>
  893. /*************************************
  894.     DoNull:
  895.     
  896.     Routine outputs a PostScript null object
  897.     
  898. **************************************/
  899. OSErr DoNull(TRDParams *rdParams)
  900.     {
  901.         OSErr            status;
  902.         
  903.         rdParams->resIndex = kDoNull;
  904.         status = RDResPrintf(rdParams);
  905.         ncheck(status);
  906.         
  907.         return(status);
  908.         
  909.     }//DoNull;
  910.  
  911.  
  912.  
  913. //<FF>
  914. /*****************************************
  915.     BeginProcSetDict:
  916.     
  917.     Routine puts dictioanary containing our procset
  918.     on top of dictionary stack
  919.     
  920. ******************************************/
  921. OSErr BeginProcSetDict(TRDParams *rdParams)
  922.     {
  923.         OSErr status;
  924.         
  925.         rdParams->resIndex = kOurDictOnStack;
  926.         status = RDResPrintf(rdParams);
  927.         ncheck(status);
  928.         
  929.         return(status);
  930.     
  931.     }//BeginProcSetDict
  932.  
  933. /*****************************************
  934.     EndProcSetDict:
  935.     
  936.     Routine removes dictioanary containing our procset
  937.     from top of dictionary stack
  938.     
  939. ******************************************/
  940. OSErr EndProcSetDict(TRDParams *rdParams)
  941.     {
  942.         OSErr status;
  943.         
  944.         rdParams->resIndex = kOurDictOffStack;
  945.         status = RDResPrintf(rdParams);
  946.         ncheck(status);
  947.         
  948.         return(status);
  949.     
  950.     }//EndProcSetDict
  951.  
  952.     
  953. //<FF>
  954. /*****************************************
  955.     GetPSFrameValue:
  956.     
  957.     Gets the frame value for the SetFrame procedure.
  958.     
  959.      0:        center-framed
  960.      1:        inside-framed
  961.     -1:        outside-framed
  962.     
  963. *******************************************/
  964. long GetPSFrameValue(gxStyleAttribute theAttributes)
  965.     {
  966.         if (theAttributes & gxInsideFrameStyle)
  967.             return(1);
  968.         else if (theAttributes & gxOutsideFrameStyle)
  969.             return(-1);
  970.         else
  971.             return(0);
  972.     
  973.     }//GetPSFrameValue
  974.     
  975.  
  976. //<FF>
  977. /********************************************
  978.     MakeShapeDict:
  979.     
  980.     Make a shape dictionary, leave it on operand stack
  981.     
  982.     hIEGlobals:            the globals handle.
  983.     theShape:                Shape to make dictionary out of.
  984.     theOptions:            requested options (not including makeProcedure, just clip/break, etc…)
  985.     
  986. *********************************************/
  987. OSErr MakeShapeDict(TIEGlobalsHdl hIEGlobals, gxShape theShape, TgeometryOptions theOptions)
  988.     {
  989.         OSErr                            status;
  990.         TIEGlobalsPtr            pGlobals;
  991.         TRDParams                    *pRDParams;
  992.         gxRectangle                shapeBounds;
  993.         gxShapeFill                theFill;
  994.         gxShapeType                theType;
  995.         fhFont                        currFont;                        // Save the font info in our globals state.
  996.         gxStyle                        currTextStyle;
  997.         Fixed                            currSize;
  998.         long                            fontChild;
  999.         gxPoint                        currTangent;
  1000.         long                            currStateFlags;
  1001.         char                            shapeTypeChar;
  1002.         
  1003.         pGlobals = *hIEGlobals;
  1004.         pRDParams = pGlobals->pRDParams;
  1005.         
  1006.         /***************
  1007.             Save the font portion of the graphics state.  
  1008.             If the shape to be dictionaryized is text/glyph/layout
  1009.             then the dictionary will need to contain font-info,
  1010.             we do not want the storage of this font info
  1011.             in the geometry procedure of the dictionary to 
  1012.             muck with what we think the graphics state is.        
  1013.         *****************/
  1014.         currStateFlags = pGlobals->ieStateFlags;
  1015.         pGlobals->ieStateFlags |= eFontOutOfDate;                    // force TextStylePrimitive to set font info. 
  1016.         currFont = pGlobals->theFont;
  1017.         fontChild = pGlobals->fontChild;
  1018.         currSize = pGlobals->fontSize;
  1019.         currTangent = pGlobals->fontTangent;
  1020.         currTextStyle = pGlobals->textStyle;
  1021.         pGlobals->textStyle = nil;                                    // We stole the style from the gloabals, forcing output of a face
  1022.                 
  1023.         
  1024.         /** Output the geometry procedure onto the operand stack **/
  1025.         
  1026.         nrequire(status = GeometryDrone(hIEGlobals, theShape, theOptions | eMakeProcedure, nil, 0), failed_Output);
  1027.         
  1028.  
  1029.         /** Output the fill key onto the operand stack **/
  1030.         
  1031.         theType = GXGetShapeType(theShape);
  1032.         if ( (theType == gxBitmapType) || (theType == gxTextType) || (theType == gxGlyphType) )
  1033.             theFill = gxNoFill;                                // PostScript proc recognizes this as a geometry that paints itself
  1034.         else
  1035.             theFill = GXGetShapeFill(theShape);
  1036.             
  1037.         status = DoFillKey(pRDParams, theFill);
  1038.         nrequire(status, failed_Output);
  1039.         
  1040.         /** Get the bounding box **/
  1041.         
  1042.         GXGetShapeBounds(theShape, 0, &shapeBounds);
  1043.  
  1044.         /** Get the character for the shape type **/
  1045.         switch(theType) {
  1046.         
  1047.             case gxRectangleType:
  1048.             case gxLineType:
  1049.             case gxPointType:
  1050.             case gxCurveType:
  1051.             case gxPolygonType:
  1052.             case gxPathType:
  1053.             case gxFullType:
  1054.             case gxEmptyType:
  1055.                 shapeTypeChar = 'g';                // geometric shape
  1056.                 break;
  1057.                 
  1058.             case gxTextType:
  1059.             case gxLayoutType:
  1060.             case gxGlyphType:
  1061.                 shapeTypeChar = 't';                // text shape
  1062.                 break;
  1063.                 
  1064.             case gxBitmapType:
  1065.                 {
  1066.                     gxBitmap        theBits;
  1067.                     GXGetBitmap(theShape, &theBits, nil);
  1068.                     if (theBits.pixelSize == 1)
  1069.                         shapeTypeChar = 'b';                                        // 1 bit bitmap
  1070.                     else
  1071.                         shapeTypeChar = 'i';                                        // deep bitmap.
  1072.                 }
  1073.                 break;
  1074.                 
  1075.             default:
  1076.                 nrequire(status = illegal_type_for_shape, failed_Output);
  1077.         
  1078.         
  1079.         }//end switch
  1080.         
  1081.         /******
  1082.             Make the shape dictionary, leave it on the operand stack
  1083.         ******/
  1084.         
  1085.         pRDParams->resIndex = kMakeShapeDict;
  1086.         status = RDResPrintf(pRDParams, shapeBounds.left, shapeBounds.top, 
  1087.                                                     shapeBounds.right, shapeBounds.bottom, &shapeTypeChar, 1);
  1088.         nrequire(status, failed_Output);
  1089.         
  1090.         status = GXGetGraphicsError(nil);
  1091.         ncheck(status);
  1092.         
  1093.  
  1094.         /** Restore the font portion of the graphics state **/
  1095.         pGlobals = *hIEGlobals;
  1096.         pGlobals->ieStateFlags = currStateFlags;
  1097.         pGlobals->theFont = currFont;
  1098.         pGlobals->fontChild = fontChild;
  1099.         pGlobals->fontSize = currSize;
  1100.         pGlobals->fontTangent = currTangent;
  1101.         if (pGlobals->textStyle != nil)                        // If creating the dict used a text style, get rid of it.
  1102.             GXDisposeStyle(pGlobals->textStyle);
  1103.         pGlobals->textStyle = currTextStyle;            // And put back the one we stole.
  1104.  
  1105.  
  1106. failed_Output:
  1107.  
  1108.         return(status);
  1109.     
  1110.     }//MakeShapeDict
  1111.  
  1112.  
  1113.  
  1114. //<FF>
  1115. /***********************************
  1116.  
  1117.     Routine:    DupShapeIfNecessary
  1118.     
  1119.     This routine is called before any modifications
  1120.     are made to a shape to facilitate PostScriptableization.
  1121.     The routine will duplicate a shape if its owner count is 
  1122.     greater than one and return the new reference in the shape's
  1123.     place.  It is up to the client to dispose of the shape
  1124.     if it was duplicated.  The client determines that a new
  1125.     shape was created by comparing the input and output shape values
  1126.     
  1127.  
  1128.     theShape:            The shape that is to be modified.
  1129.     shapeCopy:        The new shape.  (will be eqaul to theShape if no
  1130.                                     duplicate was made.)
  1131.     
  1132. ***************************************/
  1133. OSErr DupShapeIfNecessary(gxShape theShape, gxShape* shapeCopy)
  1134.     {
  1135.         if (GXGetShapeOwners(theShape) > 1)
  1136.             *shapeCopy = GXCopyToShape(nil, theShape);
  1137.         else
  1138.             *shapeCopy = theShape;    
  1139.     
  1140.         return(GXGetGraphicsError(nil));
  1141.         
  1142.     }//DupShapeIfNecessary
  1143.  
  1144.  
  1145.  
  1146. //<FF>
  1147. /**************************************
  1148.  
  1149.     Routine OutputTag:
  1150.     
  1151.     Routine buffers the data in a tag.
  1152.     Used for synonyms.
  1153.     
  1154. ***************************************/
  1155. OSErr OutputTag(TIEGlobalsHdl hGlobals, gxTag theTag)
  1156.     {
  1157.         char*            data;
  1158.         long            tagSize;
  1159.         OSErr            status;
  1160.         
  1161.         GXLockTag(theTag);
  1162.         
  1163.         data = ((char*)GXGetTagStructure(theTag, &tagSize) - tagStructureBugOffset);
  1164.     
  1165.         status = (*hGlobals)->psDevice->BufferData(data, tagSize, gxNoBufferOptions);
  1166.         
  1167.         GXUnlockTag(theTag);
  1168.  
  1169.         ncheck(status);
  1170.         
  1171.  
  1172.         return(status);
  1173.     
  1174.     }//OutputTag
  1175.  
  1176.  
  1177.  
  1178. /****************************************
  1179.  
  1180.     DoMoveto:
  1181.     Routine outputs a moveto for the specified point
  1182.     
  1183.     rdParams:                The RD parameter block.
  1184.     thePoint:                The point to move to.
  1185.     
  1186. ******************************************/
  1187. OSErr    DoMoveto(TRDParams *rdParams, gxPoint *thePoint)
  1188.     {
  1189.         OSErr                status;
  1190.         
  1191.         rdParams->resIndex = kMoveto;
  1192.         status = RDResPrintf(rdParams, thePoint);
  1193.         ncheck(status);
  1194.         return(status);
  1195.     
  1196.     }//DoMoveto
  1197.  
  1198. /****************************************
  1199.  
  1200.     DoRmoveto:
  1201.     Routine outputs a rmoveto for the specified point
  1202.     
  1203.     rdParams:                The RD parameter block.
  1204.     thePoint:                The point to rmove to.
  1205.     
  1206. ******************************************/
  1207. OSErr    DoRmoveto(TRDParams *rdParams, gxPoint *thePoint)
  1208.     {
  1209.         OSErr                status;
  1210.         
  1211.         rdParams->resIndex = kRmoveto;
  1212.         status = RDResPrintf(rdParams, thePoint);
  1213.         ncheck(status);
  1214.         return(status);
  1215.     
  1216.     }//DoRmoveto
  1217.  
  1218.  
  1219. /****************************************
  1220.  
  1221.     DoPoint:
  1222.     Routine outputs a point
  1223.     
  1224.     rdParams:                The RD parameter block.
  1225.     thePoint:                The point
  1226.     
  1227. ******************************************/
  1228. OSErr    DoPoint(TRDParams *rdParams, gxPoint *thePoint)
  1229.     {
  1230.         OSErr                status;
  1231.         
  1232.         rdParams->resIndex = kDoPoint;
  1233.         status = RDResPrintf(rdParams, thePoint);
  1234.         ncheck(status);
  1235.         return(status);
  1236.     
  1237.     }//DoPoint
  1238.  
  1239.  
  1240.  
  1241.  
  1242.  
  1243. //<FF>
  1244. /*************************
  1245.     SkiaMiterToPS:
  1246.     
  1247.     function converts a skia miter limit value
  1248.     to a PostScript miter limit value.
  1249.         
  1250. ***************************/
  1251. Fixed SkiaMiterToPS(Fixed miterValue, Fixed lineWidth)
  1252.     {
  1253.         Fixed            adjustValue;
  1254.         
  1255.         adjustValue = FixedMultiply(lineWidth, Magnitude(fixed1, miterValue << 1));
  1256.         
  1257.         if (adjustValue < fixed1)                // PostScript limitation.
  1258.             adjustValue = fixed1;
  1259.         
  1260.         return(adjustValue);
  1261.         
  1262.     }//SkiaMiterToPS
  1263.  
  1264. //<FF>
  1265. /****************************
  1266.     GetPSLineJoin:
  1267.     
  1268.     Assumes the line join is one of
  1269.     the PostScript standard joins and 
  1270.     returns the correct enumerated value.
  1271.     
  1272.     Returns -1 if join isn't postscriptable.
  1273.     
  1274. *****************************/
  1275. long GetPSLineJoin(gxJoinRecord* theJoin)
  1276.     {
  1277.         register long        psJoin;
  1278.                 
  1279.         if ( theJoin->join != nil  )            
  1280.             psJoin = -1;                                    //    PostScript can't do shape join yet.
  1281.             
  1282.         else if (theJoin->attributes == gxSharpJoin) 
  1283.             if (theJoin->miter != 0)
  1284.                 psJoin = eMiterJoin;
  1285.             else
  1286.                 psJoin = eBevelJoin;
  1287.             
  1288.         else if (theJoin->attributes == gxCurveJoin)
  1289.             psJoin = eRoundJoin;
  1290.  
  1291.         return(psJoin);
  1292.     
  1293.     }//GetPSLineJoin
  1294.  
  1295.  
  1296. //<FF>
  1297. /****************************
  1298.  
  1299.     DisposeGstateItems:
  1300.     
  1301.     Function disposes of all graphics
  1302.     objects owned by a graphics state
  1303.     record.
  1304.     
  1305.     Important to note:  the pointer
  1306.     to the graphics state could be
  1307.     pointing into an unlocked handle.
  1308.     So don't assume moving memory 
  1309.     will preserve it.
  1310.         
  1311. *****************************/
  1312. void    DisposeGstateItems(TGstate *pGstate)
  1313.     {
  1314.         gxTransform            theTransform;
  1315.         gxInk                        theInk;
  1316.         gxTag                        theHalftoneTag;
  1317.         gxColorProfile    theProfile;
  1318.         
  1319.         /** get the stuff before making any gx gra[hics calls in case they move memory **/
  1320.         
  1321.         theTransform = pGstate->theTransform;
  1322.         theInk = pGstate->theInk;
  1323.         theHalftoneTag = pGstate->halftoneTag;
  1324.         theProfile = pGstate->currProfile;
  1325.                 
  1326.         GXDisposeTransform(theTransform);
  1327.         GXDisposeInk(theInk);
  1328.         
  1329.         if (theHalftoneTag != nil)
  1330.             GXDisposeTag(theHalftoneTag);
  1331.         
  1332.         if (theProfile != nil)
  1333.             GXDisposeColorProfile(theProfile);
  1334.  
  1335.     }//DisposeGstateItems
  1336.  
  1337.  
  1338. //<FF>
  1339. /***************************
  1340.  
  1341.     Imaging engine wrapper for sending
  1342.     the buffer data message.  This wrapper
  1343.     is called to ensure that the RDUtilities
  1344.     buffer is flushed before data is sent
  1345.     directly to BufferData.
  1346.     
  1347. ****************************/
  1348. OSErr    PSIEBufferData(TIEGlobalsHdl hIEGlobals, unsigned char *data, long length, long flags)
  1349.     {
  1350.         OSErr        status;    
  1351.     
  1352.         status = RDFlushBuffer((*hIEGlobals)->rdMap);
  1353.         nrequire(status, failed_rdFlush);
  1354.         
  1355.         status = (*hIEGlobals)->psDevice->BufferData((char*)data, length, flags);
  1356.         ncheck(status);
  1357.         
  1358. failed_rdFlush:
  1359.         return(status);
  1360.     
  1361.     }
  1362.  
  1363.  
  1364.  
  1365.  
  1366.  
  1367. //<FF>
  1368. /**************************
  1369.  
  1370.     PSTextToPath:
  1371.     
  1372.     Converts a text/layout/glyph shape
  1373.     into a picture full o'paths.  One for
  1374.     each glyph.  This helps avoid limitchecks.
  1375.     
  1376. ****************************/
  1377. OSErr PSTextToPaths(gxShape theShape)
  1378.     {
  1379.         OSErr            status;
  1380.         long            i, count;
  1381.         gxShape        aShape;
  1382.     
  1383.         status = ShUDissectGlyphs(theShape, false);            // false for per glyph rather than per style.    
  1384.         if (status == shape_already_in_simple_form) {        // This means ShUDissect did nothing
  1385.         
  1386.             /* We always want a picture, even if there is only one glyph */
  1387.             GXSetShapeType(theShape, gxPictureType);
  1388.             status = GXGetGraphicsError(nil);
  1389.             
  1390.         }//end if
  1391.         nrequire(status, failed_dissect);
  1392.         
  1393.         /** Now convert each element to a path **/
  1394.         
  1395.         count = GXGetPictureParts(theShape, 1, gxSelectToEnd, nil, nil, nil, nil);
  1396.         
  1397.         for (i = 1; i <= count; ++i) {
  1398.         
  1399.             GXGetPictureParts(theShape, i, 1, &aShape, nil, nil, nil);
  1400.             
  1401.             status = TextToUnhintedPath(aShape);
  1402.             nrequire(status, failed_SetShapeType);
  1403.         
  1404.         }//end for
  1405.  
  1406. failed_SetShapeType:
  1407. failed_dissect:
  1408.         
  1409.         return(status);
  1410.     
  1411.     }//PSTextToPaths
  1412.     
  1413.     
  1414. /******************************************
  1415.  
  1416.     GetColorProfileSize
  1417.     
  1418.     if size != nil, data size returned in here.
  1419.     
  1420.     Function returns the size of the profile.
  1421.     
  1422.     If the profile is not a ColorSync version 1
  1423.     return zero, this will make the rest of the code
  1424.     think it is zero length and not do matching.  
  1425.     What else can we do??????  For more information
  1426.     Contact Steve Swen.
  1427.     
  1428.     Wouldn't need this wrapper if ColorSync 2.0
  1429.     were going to be backward compatible.
  1430.     
  1431. *******************************************/
  1432. long GetColorProfileSize(gxColorProfile theProfile, long *profileVersion)
  1433.     {
  1434.         CMProfile                *profileData;
  1435.         long                        version;
  1436.         long                        size;
  1437.         
  1438.         GXLockColorProfile(theProfile);
  1439.         profileData = (CMProfile*)GXGetColorProfileStructure(theProfile, &size);
  1440.         
  1441.         /** Treat non version 1 profiles the same as zero length profiles - no matching **/
  1442.         if ( (size > 0)  ) {
  1443.         
  1444.             version = profileData->header.applProfileVersion;
  1445.             if (version != cmCS1ProfileVersion)  {
  1446.         
  1447.                 #if DEBUGLEVEL > 1
  1448.                     /* Steve Swen is a goof */
  1449.                     dprintf(trace, "Document contained profile version: %X; disabling matching for this profile", version);
  1450.                 #endif
  1451.                 size = 0;
  1452.             
  1453.             }//end if
  1454.             
  1455.         } else {
  1456.         
  1457.             version = cmCS1ProfileVersion;
  1458.         
  1459.         }//end if
  1460.         
  1461.         GXUnlockColorProfile(theProfile);
  1462.         
  1463.         if (profileVersion != nil)
  1464.             *profileVersion = version;
  1465.  
  1466.         return(size);
  1467.     
  1468.     }//GetColorProfileVersion
  1469.  
  1470.  
  1471.